package org.duanyu.shopping_user_service.util;

import lombok.SneakyThrows;
import org.jose4j.json.JsonUtil;
import org.jose4j.jwa.AlgorithmConstraints;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.HashMap;
import java.util.Map;

public class JwtUtils {
    // 公钥
    public final static String PUBLIC_JSON = "{\"kty\":\"RSA\",\"n\":\"xXqlvvJvGxs2nbl44UhvrCGr-tI6B3GXJSaJedZUsoeYPisRQMAtlp-dglCZ0yvjk-LLMS6C5OgMutm7wAfdNFpkwzSSxESKDURAi9MLbgqPt_THA0Z2epFyBTGwTd053NVdsORc1fPcgu4aKHwHQ9bSKVgH5fN1w-dSlT85AO-ztJ9cdEGCacPVG4fwvsdDyhx49MzaQxZ9siYG66aDZykheV5AjeCFFggUsITRuxXuKRgmnD_oTMpKvH-viJKXaqSjivaxeuxQSGtSlKoD4fQnR4QmFwR93OUOlqFpCsHQxbXWPPgGs7aU-uKqnPvQh0p9nCIDbJ4JKumTrTlG1w\",\"e\":\"AQAB\"}";
    // 私钥
    public final static String PRIVATE_JSON = "{\"kty\":\"RSA\",\"n\":\"xXqlvvJvGxs2nbl44UhvrCGr-tI6B3GXJSaJedZUsoeYPisRQMAtlp-dglCZ0yvjk-LLMS6C5OgMutm7wAfdNFpkwzSSxESKDURAi9MLbgqPt_THA0Z2epFyBTGwTd053NVdsORc1fPcgu4aKHwHQ9bSKVgH5fN1w-dSlT85AO-ztJ9cdEGCacPVG4fwvsdDyhx49MzaQxZ9siYG66aDZykheV5AjeCFFggUsITRuxXuKRgmnD_oTMpKvH-viJKXaqSjivaxeuxQSGtSlKoD4fQnR4QmFwR93OUOlqFpCsHQxbXWPPgGs7aU-uKqnPvQh0p9nCIDbJ4JKumTrTlG1w\",\"e\":\"AQAB\",\"d\":\"BUQBcmd9ffAKU0dUSVGIpMLbFpuPb45gVN3Dsat846vI6_NzCNJ3BLqp1QU4LNDRRyq3d07Br7_eQwc2QecTx2cXo7rdpP0c30CwJepRNjRy45lTyysQUrFZJHlQNatN9Sz9TA-yyAOyIA2gRe8UtILgZLjTsRZ-T-R1p8QhTXyKwWwii4CJAtJSErYWToGRUyt11eBE9IK80ROvTHZ8-pjDoPZEsMDVbWShtdwKPUXPNebqyOrLvGozfqSHoH7l35k8pBY7MqBqkZQ0JEaSfwOeztWs4ADgv1wAzALjes5zI00pZFMamqqlZJmdw866u3Q9aVWkl8vVUinn9DVKmQ\",\"p\":\"1jkKMbyFi5vG-Ou9rEvRJq-cEFMy5MwpQfWpwYA-Poyoke2v9FKryRDFmVouCmwPeUcNhy9Mx2HK1g1tRVBHgkNevYxx-PQRfrQNsjFoG7Pc1NL1G9Aejz1LVL_kCAGHpmAIiXFeDYB0yAKTsmnsJAmS19m6LjXURQExmcGqH-8\",\"q\":\"6_2vr-9RPZUsHsOUgEdTBCoigTFxsoxu6B1kQ6PWztbgoN9FdVHowBbUmGr1RYqkO_BOWWzdWgUoDFQ9z6n4QkY9lhtljIaeSaIF6rypSueu5bB6R8dWVIyXubCyd2vUI9di7OqV9IvGzzRevM6RBeY-4c-6ijetjH7MiqP135k\",\"dp\":\"Pz_8KI83Bu9pohlImVSRXlC_TXqjLjaxf84e3wkUV7eEFgINz5-RJP6UuSCNM3qQXwiBkAaBLuVK1ESGnM6FLorhsCmFhTHa8IQM_y3jRTqn2xamVB3wx-4bDdzSYSLCgHceTiZw1J-2208XeLgZhtJkzuJ0PCycjfs6P-GUb3U\",\"dq\":\"RlbxHNGKN37VDb5h7vJTbjRY4IUqTHvLOug30GlvR2uIvKqP-24Un9yuNVf8D2RJm4v-7myidYh_7VzWp6UT2D0zciBsXjxpxazDcroVA7yWxuOZLvfdZYoaV0CxkSLUsnIqjE9HrwJSmcQUUNaJJ2b_azMNeNErq2rH8LL6QFE\",\"qi\":\"mgwc4DNfTLi1xhoV0NMe7l4Y_OBhl8vmToMz3j_vC51wlRJMoGs2imdx8RD4yj6S57J0SxrOA-wCC-T_58lL4hREMopUZD7sd8w4ZRhLd14C0WONULl60RChJ4rJkpi-Fftqg0pXHTpZfEqD_fPjnCueK6NU8FObyR7MBg_IiCM\"}";

    /**
     * 生成token
     *
     * @param userId    用户id
     * @param username 用户名字
     * @return
     */
    @SneakyThrows
    public static String sign(Long userId, String username) {
        // 1、 创建jwtclaims  jwt内容载荷部分
        JwtClaims claims = new JwtClaims();
        // 是谁创建了令牌并且签署了它
        claims.setIssuer("itbaizhan");
        // 令牌将被发送给谁
        claims.setAudience("audience");
        // 失效时间长 （分钟）
        claims.setExpirationTimeMinutesInTheFuture(60 * 24);
        // 令牌唯一标识符
        claims.setGeneratedJwtId();
        // 当令牌被发布或者创建现在
        claims.setIssuedAtToNow();
        // 再次之前令牌无效
        claims.setNotBeforeMinutesInThePast(2);
        // 主题
        claims.setSubject("shopping");
        // 可以添加关于这个主题得声明属性
        claims.setClaim("userId", userId);
        claims.setClaim("username", username);

        // 2、签名
        JsonWebSignature jws = new JsonWebSignature();
        //赋值载荷
        jws.setPayload(claims.toJson());

        // 3、jwt使用私钥签署
        PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(PRIVATE_JSON)).getPrivateKey();
        jws.setKey(privateKey);

        // 4、设置关键 kid
        jws.setKeyIdHeaderValue("keyId");

        // 5、设置签名算法
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
        // 6、生成jwt
        return jws.getCompactSerialization();
    }


    /**
     * 解密token，获取token中的信息
     *
     * @param token
     */
    @SneakyThrows
    public static Map<String, Object> verify(String token){
        // 1、引入公钥
        PublicKey publicKey = new RsaJsonWebKey(JsonUtil.parseJson(PUBLIC_JSON)).getPublicKey();
        // 2、使用jwtcoonsumer  验证和处理jwt
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() //过期时间
                .setAllowedClockSkewInSeconds(30) //允许在验证得时候留有一些余地 计算时钟偏差  秒
                .setRequireSubject() // 主题生命
                .setExpectedIssuer("itbaizhan") // jwt需要知道谁发布得 用来验证发布人
                .setExpectedAudience("audience") //jwt目的是谁 用来验证观众
                .setVerificationKey(publicKey) // 用公钥验证签名  验证密钥
                .setJwsAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST, AlgorithmIdentifiers.RSA_USING_SHA256))
                .build();
        // 3、验证jwt 并将其处理为 claims
        try {
            JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
            return jwtClaims.getClaimsMap();
        }catch (Exception e){
            return new HashMap<>();
        }
    }


    public static void main(String[] args){
        // 生成
        String baizhan = sign(1001L, "baizhan");
        System.out.println(baizhan);

        Map<String, Object> stringObjectMap = verify(baizhan);
        System.out.println(stringObjectMap.get("userId"));
        System.out.println(stringObjectMap.get("username"));
    }
}
